package cc.xsubj.trading.entity;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;

import cc.xsubj.trading.utilities.Direction;
import cc.xsubj.trading.world.TiledWorld;

import cc.xsubj.engine.ResourceManager;
import cc.xsubj.engine.entity.Entity;
import cc.xsubj.engine.tween.Ease;
import cc.xsubj.engine.tween.LinearMotion;
import cc.xsubj.engine.tween.Tween.TweenerMode;


public class Wizard extends Entity {
	
	public float moveDuration; //in milliseconds
	
	private TiledWorld t;
	
	private LinearMotion motion;
	
	private Direction direction = Direction.UP;
	
	private boolean justTeleported = false;

	public Wizard(float x, float y) {
		super(x, y);

		SpriteSheet sheet = ResourceManager.getSpriteSheet("wizard_sheet");
		sheet.setFilter(Image.FILTER_NEAREST);
		setupAnimations(sheet);
		
		setupKeymaps();
		
		this.moveDuration = 400;
		
		motion = new LinearMotion(this.x, this.y, this.x, this.y, 1, Ease.NONE);
		
	}

	private void setupKeymaps() {
		define("UP", Input.KEY_UP, Input.KEY_W);
		define("DOWN", Input.KEY_DOWN, Input.KEY_S);
		define("LEFT", Input.KEY_LEFT, Input.KEY_A);
		define("RIGHT", Input.KEY_RIGHT, Input.KEY_D);
		define("INTERACT", Input.KEY_X, Input.KEY_E);
	}
	
	private void setupAnimations(SpriteSheet sheet) {
		setGraphic(sheet);
		addAnimation("DOWN", false, 0, 0);
		addAnimation("UP", false, 0, 1);
		addAnimation("RIGHT", false, 0, 2);
		addAnimation("LEFT", false, 0, 3);
	}
	
	@Override
	public void addedToWorld()
	{
		t = (TiledWorld) this.world;
	}
	
	@Override
	public void update(GameContainer container, int delta) throws SlickException
	{
		super.update(container, delta);
		
		
		//The order of these next three blocks is important. It makes smooth motion.
		if (isMoving())
		{
		    justTeleported = false;
			motion.update(delta);
		}
		setPosition(motion.getPosition().x, motion.getPosition().y);
		if (!isMoving() && !t.hasMessages())
		{
		    checkTeleport();
			checkMovementKeys();
			checkInteractionKeys();	
		}
	}

    private void checkTeleport()
    {
        Interactable standingOn = t.getInteractable(getTileX(), getTileY());
        if (standingOn != null && standingOn instanceof TeleportPad && !justTeleported)
        {
            justTeleported = true;
            standingOn.interact();
        }
    }

    public boolean isMoving()
    {
        return !motion.isFinished();
    }

    private void checkInteractionKeys() {
		if (pressed("INTERACT"))
		{
			int X = getTileX();
			int Y = getTileY();
			switch(direction)
			{
			case UP:
				Y--; break;
			case DOWN:
				Y++; break;
			case LEFT:
				X--; break;
			case RIGHT:
				X++; break;
			default:
				break;
			}
			Interactable target = t.getInteractable(X, Y);
			if (target != null)
			{
				target.interact();
			}
		}
	}

    private int getTileY()
    {
        return (int)(y/t.getTileSize());
    }

    private int getTileX()
    {
        return (int)(x/t.getTileSize());
    }

	private void checkMovementKeys() {
		if (check("UP")) {
			move(0,-1);
			setAnim("UP");
			direction = Direction.UP;
		}
		else if (check("DOWN")) {
			move(0,1);
			setAnim("DOWN");
			direction = Direction.DOWN;
		}
		else if (check("LEFT")) {
			move(-1,0);
			setAnim("LEFT");
			direction = Direction.LEFT;
		}
		else if (check("RIGHT")) {
			move(1,0);
			setAnim("RIGHT");
			direction = Direction.RIGHT;
		}
	}
	
	private void setPosition(float x, float y) {
		this.x = (int)x;
		this.y = (int)y;
	}

	private void move(int dx, int dy)
	{
		if(dx != 0 && dy != 0) return;
		
		int tileSize = t.getTileSize();
		int X = (int)(x/tileSize);
		int Y = (int)(y/tileSize);
		if(canMoveTo(X+dx, Y+dy))
		{
			//motion = new LinearMotion(x, y, x+dx*tileSize, y+dy*tileSize, this.moveDuration, Ease.NONE);
			motion = new LinearMotion(x, y, x+dx*tileSize, y+dy*tileSize, 1.0f, TweenerMode.ONESHOT, moveDuration, Ease.NONE, true);
			motion.start();
		}
	}
	
	private boolean canMoveTo(int x, int y)
	{
		return !t.blocked(x, y);
	}
	
	public Direction getDirection()
	{
		return direction;
	}
}
